"""
会话服务
管理用户会话和交互状态
"""

import uuid
from typing import Dict, Any, Optional, List
from datetime import datetime, timedelta
import json
from pathlib import Path
from src.utils.logging import get_logger
from src.utils.decorators import handle_errors, timing
from src.exceptions import SessionNotFoundError, ResearchException

logger = get_logger(__name__)

class SessionService:
    """会话服务类"""
    
    def __init__(self, data_dir: str = "data/sessions"):
        self.data_dir = Path(data_dir)
        self.data_dir.mkdir(parents=True, exist_ok=True)
        self.sessions: Dict[str, Dict] = {}
        self._load_sessions()
    
    @handle_errors(default_return=None, log_level="ERROR")
    def _load_sessions(self):
        """加载持久化的会话数据"""
        try:
            session_files = list(self.data_dir.glob("*.json"))
            for session_file in session_files:
                try:
                    with open(session_file, 'r', encoding='utf-8') as f:
                        content = f.read().strip()
                        if not content:
                            logger.warning(f"会话文件为空: {session_file}")
                            continue
                        session_data = json.loads(content)
                        session_id = session_file.stem
                        self.sessions[session_id] = session_data
                except json.JSONDecodeError as e:
                    logger.warning(f"会话文件JSON格式错误 {session_file}: {e}")
                    # 尝试修复或跳过损坏的文件
                    self._handle_corrupted_session_file(session_file)
                except Exception as e:
                    logger.warning(f"加载会话文件失败 {session_file}: {e}")
            
            logger.info(f"已加载 {len(self.sessions)} 个会话")
        except Exception as e:
            logger.error(f"加载会话数据失败: {e}", exc_info=True)
    
    def _handle_corrupted_session_file(self, session_file: Path):
        """
        处理损坏的会话文件
        """
        try:
            # 备份损坏的文件
            backup_file = session_file.with_suffix('.json.corrupted')
            session_file.rename(backup_file)
            logger.info(f"已将损坏的会话文件备份为: {backup_file}")
        except Exception as e:
            logger.error(f"备份损坏的会话文件失败 {session_file}: {e}")

    @timing(log_level="DEBUG")
    def _save_session(self, session_id: str, session_data: Dict):
        """保存会话数据到文件"""
        try:
            session_file = self.data_dir / f"{session_id}.json"
            # 使用临时文件进行原子写入，避免文件损坏
            temp_file = session_file.with_suffix('.json.tmp')
            with open(temp_file, 'w', encoding='utf-8') as f:
                json.dump(session_data, f, ensure_ascii=False, indent=2)
            # 原子性地替换原文件
            temp_file.replace(session_file)
        except Exception as e:
            logger.error(f"保存会话失败 {session_id}: {e}", exc_info=True)
    
    def create_session(self, user_id: Optional[str] = None, metadata: Optional[Dict] = None) -> str:
        """
        创建新会话
        
        Args:
            user_id: 用户ID（可选）
            metadata: 会话元数据（可选）
            
        Returns:
            会话ID
        """
        session_id = str(uuid.uuid4())
        
        session_data = {
            "session_id": session_id,
            "user_id": user_id,
            "created_at": datetime.now().isoformat(),
            "updated_at": datetime.now().isoformat(),
            "interaction_count": 0,
            "research_count": 0,
            "metadata": metadata or {},
            "history": [],
            "active": True
        }
        
        self.sessions[session_id] = session_data
        self._save_session(session_id, session_data)
        
        logger.info(
            f"创建新会话: {session_id}",
            extra={"user_id": user_id, "metadata": metadata}
        )
        
        return session_id
    
    def get_session(self, session_id: str) -> Dict:
        """
        获取会话信息
        
        Args:
            session_id: 会话ID
            
        Returns:
            会话数据字典
        """
        if session_id not in self.sessions:
            raise SessionNotFoundError(session_id)
        
        return self.sessions[session_id]
    
    def update_session(self, session_id: str, updates: Dict) -> Dict:
        """
        更新会话信息
        
        Args:
            session_id: 会话ID
            updates: 更新字段
            
        Returns:
            更新后的会话数据
        """
        if session_id not in self.sessions:
            raise SessionNotFoundError(session_id)
        
        session_data = self.sessions[session_id]
        session_data.update(updates)
        session_data["updated_at"] = datetime.now().isoformat()
        
        self._save_session(session_id, session_data)
        
        return session_data
    
    def add_interaction(self, session_id: str, question: str, response: Dict) -> Dict:
        """
        添加交互记录
        
        Args:
            session_id: 会话ID
            question: 用户问题
            response: 系统响应
            
        Returns:
            更新后的会话数据
        """
        if session_id not in self.sessions:
            raise SessionNotFoundError(session_id)
        
        session_data = self.sessions[session_id]
        
        interaction = {
            "timestamp": datetime.now().isoformat(),
            "question": question,
            "response": response,
            "interaction_id": len(session_data["history"]) + 1
        }
        
        session_data["history"].append(interaction)
        session_data["interaction_count"] += 1
        session_data["updated_at"] = datetime.now().isoformat()
        
        if response.get("success", False):
            session_data["research_count"] += 1
        
        self._save_session(session_id, session_data)
        
        logger.info(
            f"添加交互记录到会话 {session_id}",
            extra={
                "interaction_id": interaction["interaction_id"],
                "question": question[:50] + "..." if len(question) > 50 else question
            }
        )
        
        return session_data
    
    def get_session_history(self, session_id: str, limit: Optional[int] = None) -> List[Dict]:
        """
        获取会话历史
        
        Args:
            session_id: 会话ID
            limit: 限制返回的记录数（可选）
            
        Returns:
            交互历史列表
        """
        if session_id not in self.sessions:
            raise SessionNotFoundError(session_id)
        
        history = self.sessions[session_id]["history"]
        
        if limit is not None:
            return history[-limit:]
        
        return history
    
    def close_session(self, session_id: str) -> Dict:
        """
        关闭会话
        
        Args:
            session_id: 会话ID
            
        Returns:
            关闭后的会话数据
        """
        if session_id not in self.sessions:
            raise SessionNotFoundError(session_id)
        
        session_data = self.update_session(session_id, {
            "active": False,
            "closed_at": datetime.now().isoformat()
        })
        
        logger.info(f"关闭会话: {session_id}")
        
        return session_data
    
    def cleanup_old_sessions(self, max_age_days: int = 30) -> int:
        """
        清理过期会话
        
        Args:
            max_age_days: 最大保留天数
            
        Returns:
            清理的会话数量
        """
        cutoff_time = datetime.now() - timedelta(days=max_age_days)
        cleaned_count = 0
        
        session_ids_to_remove = []
        
        for session_id, session_data in list(self.sessions.items()):
            updated_at = datetime.fromisoformat(session_data["updated_at"])
            
            if updated_at < cutoff_time and not session_data.get("active", True):
                session_ids_to_remove.append(session_id)
        
        for session_id in session_ids_to_remove:
            try:
                # 删除文件
                session_file = self.data_dir / f"{session_id}.json"
                if session_file.exists():
                    session_file.unlink()
                
                # 从内存中移除
                del self.sessions[session_id]
                cleaned_count += 1
                
                logger.info(f"清理过期会话: {session_id}")
                
            except Exception as e:
                logger.error(f"清理会话失败 {session_id}: {e}")
        
        return cleaned_count
    
    def get_active_sessions(self) -> List[Dict]:
        """获取所有活跃会话"""
        return [
            session_data for session_data in self.sessions.values()
            if session_data.get("active", True)
        ]
    
    def get_session_stats(self, session_id: str) -> Dict:
        """
        获取会话统计信息
        
        Args:
            session_id: 会话ID
            
        Returns:
            统计信息字典
        """
        if session_id not in self.sessions:
            raise SessionNotFoundError(session_id)
        
        session_data = self.sessions[session_id]
        history = session_data["history"]
        
        successful_research = sum(1 for item in history if item.get("response", {}).get("success", False))
        failed_research = len(history) - successful_research
        
        return {
            "session_id": session_id,
            "total_interactions": len(history),
            "successful_research": successful_research,
            "failed_research": failed_research,
            "success_rate": f"{(successful_research/len(history))*100:.1f}%" if history else "0%",
            "created_at": session_data["created_at"],
            "last_updated": session_data["updated_at"],
            "active": session_data.get("active", True)
        }
    
    def delete_session(self, session_id: str) -> bool:
        """
        删除会话
        
        Args:
            session_id: 会话ID
            
        Returns:
            是否删除成功
        """
        if session_id not in self.sessions:
            return False
        
        try:
            # 删除文件
            session_file = self.data_dir / f"{session_id}.json"
            if session_file.exists():
                session_file.unlink()
            
            # 从内存中移除
            del self.sessions[session_id]
            
            logger.info(f"删除会话: {session_id}")
            return True
        except Exception as e:
            logger.error(f"删除会话失败 {session_id}: {e}")
            return False
